package com.ecgsystem.panel;

import java.util.concurrent.ConcurrentLinkedQueue;

import com.ecgsystem.activity.OnlineECG;
import com.ecgsystem.constants.Constants;

import com.ecgsystem.activity.R;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Typeface;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ScaleGestureDetector;

/**
 * @author anhtuan
 * 
 */
public class Panel6Online extends SurfaceView implements SurfaceHolder.Callback,
		Constants {
	/*
	 * 1 o nho 1mm voi toc do 25 mm/s 1mm = 0.04s 1mm = 4px 1s = 100 px tan so
	 * lay mau a(s) lenght = 0.04/a * 62.5 = 2.5 /a khoang cach a * 25 *
	 * PixelPerMm
	 */
	private Paint grid;
	private Paint line;
	private Paint text;
	private Paint borderline;
	private Paint linebase;
	private PanelThread _thread;
	private Bitmap _bitmap;
	private float x[][];
	private float y[][];

	private boolean first = true;
	private int i = 0;

	private ConcurrentLinkedQueue<Float> QueueDraw[];

	/**
	 * TODO Put here a description of this field.
	 */
	public static int WIDTH;
	/**
	 * TODO Put here a description of this field.
	 */
	public static int HEIGHT;

	/**
	 * TODO Put here a description of this field.
	 */
	public static float baseline[];

	/**
	 * TODO Put here a description of this field.
	 */
	public static float PixelPerMm = 5;

	/**
	 * TODO Put here a description of this field.
	 */
	public static float zoom = 7;

	/**
	 * tan so lay mau f
	 */
	public static float fx = 0.002f; // 0.002s 1 mau
	
	/**
	 * toc do giay
	 */
	public static float v = 25; // 25mm/s
	// so diem ve tren ca ban
	private int ARRAYLENGHT;

	private static float MIN_ZOOM = 1f;
	private static float MAX_ZOOM = 5f;

	private float scaleFactor = 1.f;
	private ScaleGestureDetector detector;
	private PointF mid;

	/**
	 * TODO Put here a description of what this constructor does.
	 *
	 * @param context
	 */
	public Panel6Online(final Context context) {
		super(context);

		this.ARRAYLENGHT = Math.round(60 / (v * fx));// co 12 o lon
		this.x = new float[4][this.ARRAYLENGHT * 3];
		this.y = new float[12][this.ARRAYLENGHT];

		baseline = new float[4];

		// mang toa do x

		this.setVisibility(VISIBLE);
		this.setEnabled(true);
		this.setZOrderOnTop(false);

		this.borderline = new Paint();
		this.borderline.setColor(getResources().getColor(R.color.borderline));
		this.borderline.setStrokeWidth(3);

		this.text = new Paint();
		this.text.setColor(getResources().getColor(R.color.text));
		this.text.setTextSize(TEXT_ECG_SIZE);
		this.text.setTypeface(Typeface.DEFAULT_BOLD);

		this.grid = new Paint();
		this.grid.setColor(getResources().getColor(R.color.grid));
		this.grid.setStrokeWidth(1);

		this.line = new Paint(Paint.ANTI_ALIAS_FLAG);
		this.line.setStyle(Paint.Style.FILL_AND_STROKE);
		this.line.setColor(getResources().getColor(R.color.line));
		this.line.setAntiAlias(true);
		this.line.setStrokeWidth(2f);

		this.linebase = new Paint();
		this.linebase.setColor(Color.GRAY);
		this.linebase.setAntiAlias(true);
		this.linebase.setStrokeWidth(0.5f);

		this.detector = new ScaleGestureDetector(context, new ScaleListener());
		this.mid = new PointF();

		this.getHolder().addCallback(this);
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 */
	public void Reset() {
		// TODO Auto-generated method stub
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 * @param QueueDraw
	 */
	public void setQueueDraw(final ConcurrentLinkedQueue<Float> QueueDraw[]) {
		this.QueueDraw = QueueDraw;
		SurfaceHolder _holder = getHolder();
		_holder.addCallback(this);
		this._thread = new PanelThread(_holder, this._bitmap);
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 */
	public void StartDraw() {
		this._thread.start();
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 */
	public void Resume() {
		if (this._thread != null && this._thread.isAlive())
			this._thread.setRunning(true);
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 */
	public void Stop() {
		Log.d("Stop online drawing", "aa");
		if (this._thread != null && this._thread.isAlive()) {
			this._thread.StopRun();
			try {
				this._thread.join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * TODO Put here a description of what this method does.
	 *
	 */
	public void Pause(){
		Log.d("Pause online drawing", "aaa");
		this.QueueDraw = null;
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		// Let the ScaleGestureDetector inspect all events.
		if (ev.getAction() == 261) {
			float x = (ev.getX(0) + ev.getX(1)) / 2;
			float y = (ev.getY(0) + ev.getY(1)) / 2;
			this.mid.set(x, y);
		}
		this.detector.onTouchEvent(ev);
		return true;
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub

		this._bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
		WIDTH = (int) (width * this.scaleFactor);
		HEIGHT = (int) (height * this.scaleFactor);
		baseline[0] = HEIGHT / 6;
		baseline[1] = HEIGHT / 2;
		baseline[2] = 5 * HEIGHT / 6;
		float temp = v * fx * PixelPerMm;
		for (int j = 0; j < this.ARRAYLENGHT; j++) {
			for (int i = 0; i < 4; i++) {
				this.x[i][j] = temp * j + i * WIDTH / 4;
			}
		}

		Canvas c = null;
		try {
			c = holder.lockCanvas(null);
			synchronized (holder) {
				Draw(c, new Canvas(this._bitmap));
				c.restore();
			}
		} finally {
			if (c != null) {
				holder.unlockCanvasAndPost(c);
			}
		}

	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		if (this._thread != null && this._thread.isAlive()) {
			this._thread.StopRun();
		}
	}

	/**
	 * TODO Put here a description of what this method does.
	 *
	 * @param vCanvas
	 * @param iCanvas
	 */
	public void Draw(Canvas vCanvas, Canvas iCanvas) {
		// TODO Auto-generated method stub
		// Vẽ lưới n�?n
		if (this.first) {
			DrawGrid(iCanvas);
		}
		int tempi = this.i;

		if (this.QueueDraw != null && OnlineECG.startDraw == true && this.QueueDraw[0].size() > Constants.NUM_OF_SIGNAL_DRAWED) {
			for (int no = 0; no < 12; no++)
			if(Constants.hasRecord[no]){
				tempi = this.i;
				for (int j = 0; j < Constants.NUM_OF_SIGNAL_DRAWED && tempi <= this.ARRAYLENGHT - 1; j++, tempi++) {
					this.y[no][tempi] = getSignal(no);
				}
				// Vòng lặp vẽ liên tiếp nối i điểm
				int j;
				if (this.i == 0)
					j = 0;
				else
					j = this.i - 1;
				for (; j < tempi - 1; j++) {
					iCanvas.drawLine(this.x[no / 3][j], this.y[no][j], this.x[no / 3][j + 1],
							this.y[no][j + 1], this.line);
				}
			}
			if (tempi < this.ARRAYLENGHT - 1) {
				this.i = tempi;
				this.first = false;
			}
			// vẽ lại từ đầu khi đã vẽ hết khung hình
			else {
				this.i = 0;
				this.first = true;
			}
		}
		if (this._bitmap != null && vCanvas != null)
			vCanvas.drawBitmap(this._bitmap, 0, 0, null);
	}

	private float getSignal(int stt) {
		int i = stt % 3;
		if (this.QueueDraw[stt] != null && !this.QueueDraw[stt].isEmpty()) {
			float signal = baseline[i]
					- this.QueueDraw[stt].remove().floatValue() * zoom * 10;
			if (signal < baseline[i] - HEIGHT / 6) {
				signal = baseline[i] - HEIGHT / 6;
			}
			if (signal > baseline[i] + HEIGHT / 6) {
				signal = baseline[i] + HEIGHT / 6;
			}
			return signal;
		} else {
			Pause();
			return -1;
		}
	}
	
	/**
	 * TODO Put here a description of what this class does.
	 *
	 * @author ANHTUAN.
	 *         Created Sep 28, 2012.
	 */
	public class PanelThread extends Thread {
		private SurfaceHolder _surfaceHolder;
		private Bitmap bitmap;
		private boolean _run = false;

		/**
		 * TODO Put here a description of what this constructor does.
		 *
		 * @param surfaceHolder
		 * @param _bitmap
		 */
		public PanelThread(final SurfaceHolder surfaceHolder, final Bitmap _bitmap) {
			this._surfaceHolder = surfaceHolder;
			this.bitmap = _bitmap;
			this._run = true;
		}

		/**
		 * TODO Put here a description of what this method does.
		 *
		 */
		public void StopRun() {
			// TODO Auto-generated method stub
			this._run = false;
		}

		/**
		 * TODO Put here a description of what this method does.
		 *
		 * @param run
		 */
		public void setRunning(final boolean run) {
			this._run = run;
		}

		@Override
		public void run() {
			Canvas c;
			while (this._run) {
				c = null;
				try {
					Thread.sleep(Constants.SLEEPPING_TIME);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				c = this._surfaceHolder.lockCanvas(null);
				synchronized (this._surfaceHolder) {
					if (this.bitmap != null && c != null) {
						c.save();
						c.scale(Panel6Online.this.scaleFactor, Panel6Online.this.scaleFactor, Panel6Online.this.mid.x, Panel6Online.this.mid.y);

						Draw(c, new Canvas(this.bitmap));
						c.restore();
					}
				}
				if (c != null) {
					this._surfaceHolder.unlockCanvasAndPost(c);
				}
			}
		}
	}

	private void DrawGrid(Canvas c) {

		this._bitmap.eraseColor(getResources().getColor(R.color.background));
		float t = 0;
		int i = 0;
		Paint draw;
		while (t <= WIDTH) {
			if (i % 12 == 0) {
				draw = this.borderline;
			} else {
				draw = this.grid;
			}
			c.drawLine(t, 0, t, HEIGHT, draw);
			t += 5 * PixelPerMm;
			i++;
		}

		// Draw horizontal line
		t = 0;
		i = 0;
		while (t <= HEIGHT) {
			if (i % 7 == 0) {
				draw = this.borderline;
			} else {
				draw = this.grid;
			}
			c.drawLine(0, t, WIDTH, t, draw);
			t += 5 * PixelPerMm;
			i++;
		}
		for (i = 0; i < 4; i++) {
			for (int j = 0; j < 3; j++) {
				c.drawText(TYPE_ECG[j * 4 + i], R.dimen.ecg_name_margin, PixelPerMm + R.dimen.ecg_name_margin, this.text);
			}
		}
	}

	private class ScaleListener extends
			ScaleGestureDetector.SimpleOnScaleGestureListener {
		@Override
		public boolean onScale(ScaleGestureDetector detector) {
			Panel6Online.this.scaleFactor *= detector.getScaleFactor();
			Panel6Online.this.scaleFactor = Math.max(MIN_ZOOM, Math.min(Panel6Online.this.scaleFactor, MAX_ZOOM));
			invalidate();
			return true;
		}
	}

	public void surfaceCreated(SurfaceHolder arg0) {
		// TODO Auto-generated method stub.
		
	}
}